/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.dto.BrandShopDTO;
import com.yami.shop.bean.enums.EsOperationType;
import com.yami.shop.bean.event.EsProductUpdateEvent;
import com.yami.shop.bean.model.Brand;
import com.yami.shop.bean.model.BrandLang;
import com.yami.shop.bean.model.BrandShop;
import com.yami.shop.bean.model.Category;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.enums.StatusEnum;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.i18n.LanguageEnum;
import com.yami.shop.common.util.PageAdapter;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.dao.BrandMapper;
import com.yami.shop.dao.BrandShopMapper;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.service.BrandLangService;
import com.yami.shop.service.BrandService;
import com.yami.shop.service.CategoryBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author lgh
 * @date 2018/07/05
 */
@Service
public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand> implements BrandService {

    @Autowired
    private BrandMapper brandMapper;

    @Autowired
    private BrandLangService brandLangService;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private BrandShopMapper brandShopMapper;

    @Autowired
    private CategoryBrandService categoryBrandService;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    public IPage<Brand> page(PageParam<Brand> page, Brand brand) {
        page.setRecords(brandMapper.list(new PageAdapter(page), brand));
        page.setTotal(brandMapper.listTotal(brand));
        loadBrandList(I18nMessage.getLang(), page.getRecords());
        return page;
    }

    @Override
    public List<Brand> listByParams(Brand brand) {
        return brandMapper.listByParams(brand, I18nMessage.getLang());
    }

    @Override
    public IPage<Brand> pageAvailableBrandByCategoryIdAndBrandNameAndShopId(PageParam<Brand> page, Long categoryId, String brandName, Long shopId) {
        return brandMapper.pageSigningByShopIdAndBrandNameAndCategoryId(page, categoryId, brandName, shopId, I18nMessage.getLang());
    }

    @Override
    public void updateShopIdAndStatusByShopId(Long oldShopId, Integer status, Long newShopId) {
        brandMapper.updateShopIdAndStatusByShopId(oldShopId, status, newShopId);
    }

    @Override
    public Brand getByBrandId(Long brandId, Integer lang) {
        if (Objects.isNull(brandId) || Objects.equals(brandId, Constant.ZERO_LONG)) {
            return null;
        }
        Brand brand = brandMapper.getByBrandId(brandId);
        loadBrandName(lang, brand);
        return brand;
    }

    @Override
    public Brand getInfo(Long brandId) {
        Brand brand = brandMapper.getByBrandId(brandId);
        if (Objects.isNull(brand)) {
            return new Brand();
        }
        List<Category> category = categoryBrandService.getCategoryByBrandId(brandId);
        if (CollUtil.isNotEmpty(category)){
            brand.setCategories(category);
        }
        return brand;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBrand(Brand brand) {
        brand.setFirstLetter(brand.getFirstLetter().toUpperCase());
        brand.setStatus(StatusEnum.ENABLE.value());

        List<BrandLang> brandLangList = brand.getBrandLangList();
        // 查询国际化表品牌名是否重复
        List<BrandLang> list = brandLangService.list(new LambdaQueryWrapper<BrandLang>().eq(BrandLang::getName, brandLangList.get(0).getName())
                .or().eq(BrandLang::getName, brandLangList.get(1).getName()));
        //判断品牌名称是否重复
        if (!list.isEmpty()){
            throw new YamiShopBindException("品牌名称不能重复");
        }

        save(brand);
        brandLangService.saveBrandLang(brand.getBrandLangList(), brand.getBrandId());
        if (CollUtil.isNotEmpty(brand.getCategoryIds())){
            categoryBrandService.saveByCategoryIds(brand.getBrandId(), brand.getCategoryIds());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> updateBrand(Brand brand) {
        brandMapper.updateById(brand);
        brandLangService.updateBrandLang(brand.getBrandLangList(), brand.getBrandId());
        categoryBrandService.updateByCategoryIds(brand.getBrandId(), brand.getCategoryIds());
        List<Long> prodIds = productMapper.listIdByBrandId(brand.getBrandId());
        eventPublisher.publishEvent(new EsProductUpdateEvent(null, prodIds, EsOperationType.UPDATE_BATCH));
        return prodIds;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> deleteById(Long brandId) {
        if (brandMapper.getUseNum(brandId) > 0){
            throw new YamiShopBindException("yami.product.brand.not.delete");
        }
        brandMapper.deleteById(brandId);
        List<Long> prodIds = productMapper.listIdByBrandId(brandId);
        eventPublisher.publishEvent(new EsProductUpdateEvent(null, prodIds, EsOperationType.UPDATE_BATCH));
        brandLangService.remove(new LambdaQueryWrapper<BrandLang>().eq(BrandLang::getBrandId, brandId));
        categoryBrandService.deleteByBrandId(brandId);
        brandShopMapper.delete(Wrappers.lambdaQuery(BrandShop.class).eq(BrandShop::getBrandId, brandId));
        return prodIds;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> updateBrandStatus(Brand brand) {
        Brand dbBrand = brandMapper.getByBrandId(brand.getBrandId());
        if (Objects.isNull(dbBrand) || dbBrand.getStatus().equals(brand.getStatus())) {
            return null;
        }
        brandMapper.updateBrandStatus(brand);
        List<Long> prodIds = productMapper.listIdByBrandId(brand.getBrandId());
        // 查询出秒杀or团购的商品进行下线
        eventPublisher.publishEvent(new EsProductUpdateEvent(null, prodIds, EsOperationType.UPDATE_BATCH));
        return prodIds;
    }

    @Override
    @Cacheable(cacheNames ="brandList", key = "#categoryId + ':' + #lang")
    public List<Brand> listByCategory(Long categoryId, Integer lang) {
        return brandMapper.listByCategoryIdAndName(categoryId, null, I18nMessage.getLang());
    }

    @Override
    public void removeCache(List<Long> categoryIds) {
        List<String> keys = new ArrayList<>();
        if (CollUtil.isNotEmpty(categoryIds)) {
            Set<Long> categoryIdSet = new HashSet<>(categoryIds);
            for (Long categoryId : categoryIdSet) {
                keys.add("brandList" + Constant.UNION + categoryId + Constant.COLON + LanguageEnum.LANGUAGE_ZH_CN.getLang());
                keys.add("brandList" + Constant.UNION + categoryId + Constant.COLON + LanguageEnum.LANGUAGE_EN.getLang());
            }
        }
        RedisUtil.del(keys);
    }
    @Override
    public List<Brand> listByCategoryIdAndName(Long categoryId, String brandName) {
        return brandMapper.listByCategoryIdAndName(categoryId, brandName, I18nMessage.getLang());
    }

    @Override
    public List<Brand> listByBrandIds(Set<Long> brandIds) {
        if (CollUtil.isEmpty(brandIds)) {
            return null;
        }
        List<Brand> brandList = brandMapper.listByBrandIds(brandIds);
        loadBrandList(I18nMessage.getLang(), brandList);
        return brandList;
    }

    private void loadBrandList(Integer lang, List<Brand> brandList) {
        if (CollUtil.isEmpty(brandList)) {
            return;
        }
        for (Brand brand : brandList) {
            loadBrandName(lang, brand);
        }
    }

    private void loadBrandName(Integer lang, Brand brand) {
        if (Objects.isNull(brand) || CollUtil.isEmpty(brand.getBrandLangList())) {
            return;
        }
        Map<Integer, String> langMap = brand.getBrandLangList().stream().collect(Collectors.toMap(BrandLang::getLang, BrandLang::getName));
        if (langMap.containsKey(lang)) {
            brand.setName(langMap.get(lang));
            return;
        }
        brand.setName(langMap.get(Constant.DEFAULT_LANG));
    }


    @Override
    public void insertBatchByBrandShopList(List<BrandShopDTO> brandShopList) {
        brandMapper.insertBatchByBrandShopList(brandShopList);
    }

}
